#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
	#include <winsock2.h>
	#include <Windows.h>
#else
	#include <signal.h>
#endif
#include "router.h"
#include "GXCfunction.h"
#include "LuaInterface.h"
#include "ikcp.h"
#include "memAlloca.h"




#ifdef ENABLE_ENCRYPT
char *g_e_key = NULL;
#endif
GameTime *g_time = 0;
ALog *g_log;
ALog *g_yylog;
ARand *g_rand = 0;
GXContext *g_gx1 = 0;

int g_stop_loop = 0;


// 前置声明 
void __installHandler();
int init_redis_thread(void *gx);
int redis_thread_frame();




#ifndef WIN32
int daemonize(const char *dir)
{
	printf("daemonize ...\n");
	switch(fork()){
		case -1:
		printf("fork() return -1\n");
		exit(-1);
		case 0:
		break;
		default:
		printf("parent exit() normally\n");
		exit(0);
	}
	if(setsid() == -1){
		exit(0);
	}
	if(dir != NULL){
		if(chdir(dir) == -1){
			exit(0);
		}
	}
	


	if(close(STDIN_FILENO) == -1){
		exit(0);
	}
	if(close(STDOUT_FILENO) == -1){
		exit(0);
	}
	if(close(STDERR_FILENO) == -1){
		exit(0);
	}

	int fd = open("/dev/null", O_RDWR, 0);
	if(fd == -1){
		exit(0);
	}
	if(dup2(fd, STDIN_FILENO) == -1){
		exit(0);
	}
	if(dup2(fd, STDOUT_FILENO) == -1){
		exit(0);
	}
	if(dup2(fd, STDERR_FILENO) == -1){
		exit(0);
	}


	return 0;
}
#endif


#define __ARENA_NUM 16
static u32 s_next_arena = 0;
static void* s_arena[__ARENA_NUM];

void* __alloca(size_t n){
	u32 idx = s_next_arena % __ARENA_NUM;
	++s_next_arena;

	void *p = myAlloca(s_arena[idx], (n/BLOCK_SIZE)+1);
	if(p){
		return p;
	}

	return new char[n];
}

void __dealloca(void* a){
	printf("dealloca  %p\n", a);

	bool ok = false;
	FOR(i, __ARENA_NUM){
		if(myCheckMem(s_arena[i], a)){
			myDealloca(s_arena[i], a);
			ok = true;
			break;
		}
	}

	if(!ok){
		delete [] (char*)a;
	}
}


int main(int argc, char** argv) {
	if(argc < 2){
		printf("argv error.\n");
		return -1;
	}
	

#ifdef ENABLE_ENCRYPT
	// 设置秘钥 
	g_e_key = (char*)malloc(256);
	FOR(i,256){
		g_e_key[i] = 'a'+(i%50);
	}
#endif	
	
	__installHandler();
	
	
	// 初始化时间 
	g_time = new GameTime();
	g_time->init();
	
	g_rand = new ARand((u32)g_time->getANSITime());
	
	
	// init log
	g_log = new ALog();
	char buf1[64];
	snprintf(buf1,60,"log%s",argv[1]);
	if(!g_log->init(buf1)){
		printf("Log init error\n");
		_exit(-1);
	}
	g_log->setTimer(g_time);
	
	g_yylog = new ALog();
	snprintf(buf1,60,"YY%s",argv[1]);
	if(!g_yylog->init(buf1)){
		printf("YYLog init error\n");
		_exit(-1);
	}
	g_yylog->setTimer(g_time);
	
	
	//init_redis_thread();

	if(argc >=3 && 0==strcmp(argv[2],"-d")){
		daemonize(NULL);
	}

	//struct sched_param sch_param;
	//sch_param.sched_priority = 1;
	//sched_setscheduler(getpid(), SCHED_RR,&sch_param);


	// init Arenas
	FOR(i, __ARENA_NUM){
		s_arena[i] = makeArena();
	}

	ikcp_allocator(__alloca, __dealloca);
	
	
	// 初始化GX上下文
	LuaInterface *boss = new LuaInterface();
	boss->SetGlobal("g_tag",0);
	boss->SetGlobal(LUA_GX_ID,argv[1]);
	boss->SetGlobal("g_node_id",argv[1]);
	
	boss->doFile("./lua/init.lua");
	
	
	// 初始化GX上下文
	int config_maxconn = boss->callGlobalFunc<int>("getMaxConn");
	int config_readbuflen = boss->callGlobalFunc<int>("getReadBufLen");
	int config_writebuflen = boss->callGlobalFunc<int>("getWriteBufLen");
	
	std::string my_port_udp = boss->callGlobalFunc<std::string>("getMyUDPPort");
	std::string my_port = boss->callGlobalFunc<std::string>("getMyPort");


	g_gx1 = new GXContext();
	bool r = g_gx1->init(GXContext::typeFullFunction,argv[1],config_maxconn,config_readbuflen,config_writebuflen,config_readbuflen, config_writebuflen);
	strncpy(g_gx1->udp_ip_and_port_,my_port_udp.c_str(),127);
	strncpy(g_gx1->tcp_ip_and_port_,my_port.c_str(),127);

	gx_set_context(g_gx1);

	// the only worker do everything...
	LuaInterface *worker1 = new LuaInterface();
	gxRegisterCFunctions(worker1->L());
	worker1->SetGlobal("g_tag",3);
	worker1->doFile("./lua/init.lua");

	lua_newtable(worker1->L());
	g_gx1->lua_stack_indicator_[0] = lua_gettop(worker1->L());

	g_gx1->regVMHandle((int)GXContext::vmhandleUDP, worker1->L(), "OnKCPReq");
	g_gx1->regVMHandle((int)GXContext::vmhandleHTTPResponse, worker1->L(), "HttpResponse2");
	g_gx1->regVMHandle((int)GXContext::vmhandleHTTPRequest, worker1->L(), "OnHttpReq2");


	init_redis_thread(g_gx1);

	worker1->callGlobalFunc<void>("readyRun", 0);
	
	
#ifdef ENABLE_ENCRYPT
	g_gx1->enable_encrypt_ = true;
#endif


	if(!g_gx1->start_listening_udp()){
		_exit(-1);
	}
	if(!g_gx1->start_listening_tcp()){
		_exit(-1);
	}
	
	
	// 进入主循环 
	static int frame_time_max = 10;		// 每帧最多让CPU等待10个千分之一秒 
	
	printf("server inited. start running...\n");

	u64 counter = 0;
	
	while(0 == g_stop_loop){
		++counter;

		g_time->setTime();
		timetype now = g_time->currentTime();
		g_time->incLocalFrame();
		
		g_gx1->cur_frame_gametime_ = now;
		g_gx1->frame_poll(now,frame_time_max);

		redis_thread_frame();
		
		// 内部时间驱动
		worker1->callGlobalFunc<void>("OnFrame");
		
		
		g_gx1->frame_flush(now);

		if(0 == (counter%10000)){
			if(g_yylog){
				g_yylog->flush();
			}
		}
	}
	
	
	printf("exit main_loop\n");
	fprintf(stderr,"exit main_loop\n");
	
	
	return 0;
}


void __defaultHandler(int sig)
{
#ifndef WIN32
	printf("signal  %d  got\n",sig);
	if(SIGSEGV == sig){
		_exit(-1);
	}

	if(SIGINT == sig){
		_exit(-2);
	}
#endif
}

void __installHandler()
{
#ifndef WIN32
    signal(SIGHUP,   __defaultHandler);   /* 1 : hangup */
    signal(SIGINT,   __defaultHandler);   /* 2 : interrupt (rubout) */
    signal(SIGQUIT,  __defaultHandler);   /* 3 : quit (ASCII FS) */
    signal(SIGILL,   __defaultHandler);   /* 4 : illegal instruction */
    signal(SIGTRAP,  __defaultHandler);   /* 5 : trace trap */
    signal(SIGABRT,  __defaultHandler);   /* 6 : abort,replace SIGIOT in the future */
    signal(SIGBUS,  SIG_IGN);   /* 7: BUS error */
    signal(SIGFPE,   __defaultHandler);   /* 8 : floating point exception */
    signal(SIGKILL,  __defaultHandler);   /* 9 : Kill process */
    signal(SIGSEGV,  __defaultHandler);   /* 11 : segmentation violation */

    signal(SIGPIPE,  SIG_IGN); /* 13 : write on a pipe with no one to read it */
    signal(SIGALRM,  SIG_IGN);   /* 14 : alarm clock */
    signal(SIGTERM,  __defaultHandler);   /* 15 : software termination signal from kill */
    signal(SIGSTKFLT,  __defaultHandler);   /* 16 : Stack fault */
    //signal(SIGCHLD,  func);   /* 17 :Child status has changed*/
    //signal(SIGCONT,  SIG_IGN);   /* 18 :Continue*/
    //signal(SIGSTOP,   func);   /* 19 : Stop, unblockable*/
    //signal(SIGTSTP, func);   /* 20 : Keyboard stop */
    signal(SIGTTIN,   SIG_IGN);   /* 21 : Background read from tty*/
    signal(SIGTTOU,    SIG_IGN);   /* 22 : Background write to tty */
    //signal(SIGURG,    SIG_IGN);   /* 23 : Urgent condition on socket */

    //signal(SIGXCPU,  SIG_IGN);   /* 24 : CPU limit exceeded*/
    signal(SIGXFSZ,  __defaultHandler);   /* 25 : File size limit exceeded */
    //signal(SIGVTALRM,  SIG_IGN);   /* 26 : Virtual alarm clock*/
    //signal(SIGPROF,  SIG_IGN);   /* 27 : Profiling alarm clock */
    //signal(SIGWINCH,SIG_IGN);   /* 28 : Window size change */
    //signal(SIGIO,  func);   /* 29 : I/O now possible */
    signal(SIGPWR,  __defaultHandler);   /* 30 : Power failure restart*/
    //signal(SIGSYS,  func);   /* 31 : Bad system call */
#endif
}

